/*
 * Copyright (c) 2010, Christian Lerche
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the Institute nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * Author: Christian Lerche <christian.lerche@uni-rostock.de>
 *
 */

#ifndef DPWS_H_
#define DPWS_H_

#include "http.h"
#include "sendm.h"

#ifndef UDPWS_MAX_TCP_CONNECTIONS
#define UDPWS_MAX_TCP_CONNECTIONS          1
#endif

#define DPWS_OK                       0
#define DPWS_ERR_MEM                 -1
#define DPWS_ERR_PARSE               -2
#define DPWS_ERR_UDP_BUT_NO_DISC     -3 /*If the message was sent over UDP but is not WS-Discovery*/
#define DPWS_ERR_NOT_IMPLEMENTED     -4
#define DPWS_ERR_NO_MATCH            -5 /*e.g. Probe and Resolve */
#define DPWS_ERR_RETRANSMISSION      -6 /* only for udp */

#define DPWS_HTTP_OK                  200
#define DPWS_HTTP_ERR_CLIENT          400
#define DPWS_HTTP_ERR_SERVER          500

#define DPWS_TRUE                     1
#define DPWS_FALSE                    0
/*TODO*/
//#define UUID_LEN            36
#define CONST_STRLEN(str)                (sizeof(str) - 1)
#define UDPWS_DISCOVERY_STACK_SIZE    46
#define UDPWS_DISCOVERY_MAX_ITEMS     50
#define SENDM_MAX_ITEMS               100
#define RETRANS_MAX_MSGID_LEN         45 //expected: urn:uuid:4b019c46-051d-11df-9aa2-0013773b416e
/*TODO: what is the max value?*/
#if UIP_CONF_IPV6
/* IPv6 (54 bytes): http://[aaaa:bbbb:cccc:dddd:eeee:ffff:gggg:hhhh]:abcd/ */
#define UDPWS_TRANSPORT_ADDR_SIZE     55 /*1 byte \0*/
#else /* UIP_CONF_IPV6 */
/* IPv4 (28 bytes): http://xxx.xxx.xxx.xxx:abcd/ */
#define UDPWS_TRANSPORT_ADDR_SIZE     30
#endif /* UIP_CONF_IPV6 */

extern char http_transport_addr[UDPWS_TRANSPORT_ADDR_SIZE];
extern int http_transport_addr_len;

//#define UDPWS_CREATE_ACTION_LIST(name)               struct dpws_service_action_s name[] = {
//#define UDPWS_ADD_ACTION(action, callback)           {action, sizeof(action), callback)}
//#define UDPWS_END_ACTION_LIST(name)                  };

#define SH_RELATESTO             0x01
#define SH_TO                    0x02
#define SH_MESSAGEID             0x04
#define SH_APPSEQ                0x08

#define NS_WSD                   0x01
#define NS_WSM                   0x02
#define NS_WSDP                  0x04
#define NS_WSE                   0x08
#define NS_SERVICES              0x10

#define DPWS_FINISH_SOAP(sm)     sendm_add_end_rom(sm, soap_end, soap_end_len)

/* struct for representing the soap header*/
struct soap_header_s{
	char* MessageID;
	int MessageID_len;
    char* Action;
    int Action_len;
    char* ReplyTo;
    int ReplyTo_len;
    char* To;
    int To_len;
    struct sendm_s *sm; /* TODO: not the right place*/
};

typedef int (*udpws_service_action_f)(struct soap_header_s *sh, char* body, int body_len, struct sendm_s *sm, struct stack_s *stack);

struct dpws_service_action_s{
	const char* Action;
	/*TODO: necessary?*/
	int Action_len;
	udpws_service_action_f callback;
};

struct hosted_service_s{
	const char* path;                       /**< e.g. "/sampleservice" */
	const int path_len;
	/*TODO: good idea? Better: Device use Service ns???*/
	const char* namespace_def;              /**< Namespace of Service, NULL --> use Device namespace*/
	const int namespace_def_len;
	const char* type;
	const int type_len;
	const char* type_def;
	const int type_def_len;
	const char* serviceid;
	const int serviceid_len;
	const char* metadata_section;           /**< WSDL or WSDL Reference*/
	const int metadata_section_len;
	const int actions_count;
	const struct dpws_service_action_s actions[];
};

struct dpws_device_s{
	const char* uuid;
	const uint16_t uuid_len;
	const char* metasec_ThisDevice;
	const int metasec_ThisDevice_len;
	const char* metasec_ThisModel;
	const int metasec_ThisModel_len;
	const char* metadataversion;
	const int metadataversion_len;
	const char* serviceid;
	const int serviceid_len;
	struct process *process;
	const int service_count;
	const struct hosted_service_s *services[];
};

struct dpws_conn_s{ /* TODO: merge all the structs in ONE big struct to minimize references?*/
	struct uip_conn *tcp_conn;  /**< The current TCP connection. */
	struct http_con hc;         /**< The http connection. */
	struct sendm_s sm;          /**< The sending machine for Response */
	struct stack_s stack;       /**< The stack for processing */
};

struct dpws_s{
	const struct dpws_device_s *device;
	/* connections */
	/*TODO: should not be here*/
	struct dpws_conn_s *conn; /* The current connection we handle (at the moment) */
	struct dpws_conn_s conns[UDPWS_MAX_TCP_CONNECTIONS];
};


struct retrans_cache_s{
	struct retrans_cache_s *next;
	uint8_t used;
	char buf[RETRANS_MAX_MSGID_LEN];
};

/* THIS MUST BE DEFINED BY THE DEVICE IMPLEMENTATION */
extern const struct dpws_device_s udpws_device;
void dpws_retrans_init();
void dpws_init_InstanceId_and_uuid(uint32_t instance_id);
int dpws_process(const struct dpws_device_s *dev, char* msg, char* msg_end, struct stack_s *stack, struct sendm_s *sm, int udp);
int dpws_gen_header(uint8_t header_conf, uint8_t ns_conf, const char* ns, const int ns_len, const char* action, const int action_len, struct sendm_s* sm, struct soap_header_s* sh, const struct dpws_device_s *dev);

#if UDPWS_CONF_WSDISCOVERY_HELLO
int dpws_gen_hello(const struct dpws_device_s *dev, struct sendm_s *sm);
#endif /* UDPWS_CONF_WSDISCOVERY_HELLO */

#endif /* DPWS_H_ */
